﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

using Pg.BioMedics.SDR.ServiceAgents.Configuration;

namespace Pg.BioMedics.SDR.ServiceAgents
{
    /// <summary>
    /// Provides access to external services agents
    /// </summary>
    public sealed class ServiceAgentsContext : IDisposable
    {
        #region Fields

        private ASRAgent asrAgent;

        #endregion

        #region Constructors

        public ServiceAgentsContext()
        {
            // register SSL certification validation callback
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets initialized instance of ASRAgent. This propert supports 
        /// service agnets lazy init
        /// </summary>
        public ASRAgent ASRAgent
        {
            get
            {
                if (this.asrAgent == null)
                    this.asrAgent = new ASRAgent(GetActiveEndpoints(ServiceElement.ASRService).FirstOrDefault(), 
                                                 CreateSecurityStrategy(ServiceElement.ASRService));

                return this.asrAgent;
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {

        }

        #endregion

        #region Support static methods

        private static bool ValidateServerCertificate(object sender,
                                                      X509Certificate certificate,
                                                      X509Chain chain,
                                                      SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }

        #endregion

        #region Support methods

        /// <summary>
        /// Create security strategy for given service name according to the configuration. 
        /// By default, if service could not be located in the configuration file 
        /// Windows security strategy is created.
        /// </summary>
        /// <param name="serviceName">Remote service name</param>
        /// <returns>Security strategy implementation</returns>
        private ISecurityStrategy CreateSecurityStrategy(string serviceName)
        {
            ServiceAgentsSection configuration = ServiceAgentsSection.GetConfiguration();
            ServiceElement serviceConfiguration = configuration.Services[serviceName];
            if (serviceConfiguration == null)
                return new WindowsSecurityStrategy();

            if (serviceConfiguration.Credentials == null)
                return new WindowsSecurityStrategy();

            if (serviceConfiguration.Credentials.Mode == ServiceCredentialsElement.WindowsMode)
                return new WindowsSecurityStrategy();
            else
                return new BasicSecurityStrategy(serviceConfiguration.Credentials.UserName, serviceConfiguration.Credentials.Password);
        }

        /// <summary>
        /// Gets list of active configured endpoints for given service
        /// </summary>
        /// <param name="serviceName">Remote service name</param>
        /// <returns>List of endpoints</returns>
        private IList<string> GetActiveEndpoints(string serviceName)
        {
            ServiceAgentsSection configuration = ServiceAgentsSection.GetConfiguration();
            ServiceElement serviceConfiguration = configuration.Services[serviceName];
            if (serviceConfiguration == null)
                return new List<string>();

            return serviceConfiguration.Endpoints.ActiveEndpoints;
        }

        #endregion
    }
}
